<script setup lang="ts">
import { ref, computed, useAttrs, PropType } from 'vue'
import { t } from '@/lang'
import { Search } from '@element-plus/icons-vue'

const emit = defineEmits(['change'])
const props = defineProps({
    is: {
        type: String,
        default: ''
    },
    asyncClose: {
        type: Boolean as PropType<boolean>,
        default: false
    },
    selectFilter: {
        type: Function as PropType<(item: ITreeItem) => boolean>,
        default: () => (item: ITreeItem) => !!item
    },
    leafOnly: {
        type: Boolean as PropType<boolean>,
        default: false
    },
    checkStrictly: {
        type: Boolean as PropType<boolean>,
        default: false
    },
    hideContent: {
        type: Boolean as PropType<boolean>,
        default: false
    }
})
/** 显示/隐藏 */
const visible = ref<boolean>()
const attrs = useAttrs()
const title = ref('')

const fullscreen = ref(false)

/**
   * @description 弹框属性
   */
const dialogAttrs = computed(() => {
    return {
        width: '800px',
        showClose: true,
        title: title.value,
        appendToBody: true,
        ...attrs
    }
})

/**
 * @description 显示弹框
 */
function show (t: string, data: ITreeItem[], selected: ITreeItem[] = []) {
    visible.value = true
    title.value = t
    list.value = data
    selection.value = selected
}

function setList (data: ITreeItem[]) {
    list.value = data
}
function setSelection (selected: ITreeItem[] = []) {
    selection.value = selected
}

function close () {
    visible.value = false
}

/**
   * @description 关闭弹框
   */
function handleCancel () {
    visible.value = false
}

/**
 * @description 打开
 */
function handleOpened () {
    // 设置选中项
    treeRef.value?.setCheckedNodes(selection.value)
    // 重新获取
    handleSelect()
}

/**
   * @description 保存
   */
function handleSave () {
    close()
    emit('change', selection.value)
}

const defaultProps = {
    children: 'children',
    label: 'label',
    value: 'value'
}

const keyword = ref('')
// 树组件
const treeRef = ref()
// 选中项
const selection = ref<any[]>([])

// 数据
const list = ref<ITreeItem[]>([])

/**
 * 选择
 * @param value
 * @param node
 */
function handleSelect () {
    if (props.hideContent) return
    const list: ITreeItem[] = treeRef.value?.getCheckedNodes(props.leafOnly)
    selection.value = list.filter(props.selectFilter)
}

/**
 * 清除
 */
function handleClear () {
    // 清空选中项
    treeRef.value?.setCheckedNodes([])
    // 重新获取
    handleSelect()
}
/**
 * 移除
 * @param item
 * @param index
 */
function handleRemove (item: ITreeItem, index:number) {
    // 更新选中项
    treeRef.value?.setChecked(item.value, false, true)
    // 重新选择
    handleSelect()
}

/**
 * 搜索
 */
function handleSearch () {
    treeRef.value?.filter(keyword.value)
}

/**
 * 筛选节点
 * @param value
 * @param data
 */
function filterNode (value:string, data: ITreeItem) {
    return data.label.indexOf(value) !== -1
}

defineExpose({
    show,
    close,
    setList,
    setSelection
})
</script>

<template>
  <el-dialog
    draggable
    class="f-dialog"
    v-model="visible"
    v-bind="dialogAttrs"
    :fullscreen="fullscreen"
    @closed="fullscreen = false"
    @opened="handleOpened"
  >
    <template #header>
      <div class="dialog-title">{{ title }}</div>
    </template>
    <div class="dialog-search">
      <slot name="search"></slot>
    </div>
    <div v-if="!hideContent" class="dialog-body">
      <div class="left">
        <el-input class="search" v-model="keyword" :prefixIcon="Search" placeholder="请输入搜索内容" clearable @change="handleSearch"></el-input>
        <div class="flex-1 w-full overflow-hidden">
          <el-scrollbar height="100%">
            <el-tree
              ref="treeRef"
              class="pt-[10px] pb-[10px]"
              :data="list"
              :props="defaultProps"
              :node-key="'value'"
              :show-checkbox="true"
              :expand-on-click-node="true"
              :check-on-click-node="false"
              :check-strictly="checkStrictly"
              :filter-node-method="filterNode"
              @check="handleSelect"
            >
            <template #default="{ node, data }">
              <span class="flex items-center">
                <slot name="tree-icon" :node="node" :data="data"></slot>
                <span>{{ node.label }}</span>
              </span>
            </template>
            </el-tree>
          </el-scrollbar>
        </div>
      </div>
      <div class="right">
        <div class="title flex items-center">
          <div class=" flex-1">已选择({{ selection.length }})</div>
          <el-button type="primary" text @click="handleClear">{{t('form.clear')}}</el-button>
        </div>
        <div class="flex-1 w-full overflow-hidden">
          <el-scrollbar height="100%">
            <div class="item flex items-center h-[34px]" v-for="(item, index) in selection" :key="index">
              <div class="flex-1">{{ item.label }}</div>
              <el-button class="item-remove" text @click="handleRemove(item, index)">
                <el-icon><Close /></el-icon>
              </el-button>
            </div>
          </el-scrollbar>
        </div>
      </div>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="handleCancel">{{ t('form.cancel') }}</el-button>
        <el-button type="primary" @click="handleSave">{{ t('form.confirm') }}</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">
  .dialog-opt {
    display: flex;
    position: absolute;
    top: 0;
    right: 0;
    align-items: center;
    justify-content: center;
    padding: 0 10px;
  }

  .dialog-opt-item {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 48px;
    cursor: pointer;
  }
  .el-tree {

    --el-tree-node-content-height: 30px;
  }
  .dialog-body {
    height: 50vh;
    width: 100%;
    display: flex;

    .left {
      flex: 1;
      height: 100%;
      border: var(--el-border);
      border-radius: var(--el-border-radius-base);
      box-sizing: border-box;
      display: flex;
      flex-direction: column;

      .search {
        height: 40px;
        border-bottom: var(--el-border);
        :deep(.el-input__wrapper) {
          box-shadow: none;
        }
      }
    }
    .right {
      flex: 1;
      height: 100%;
      border: var(--el-border);
      border-radius: var(--el-border-radius-base);
      margin-left: 20px;
      display: flex;
      flex-direction: column;

      .title {
        color: #999;
        padding: 5px 10px;
        border-bottom: var(--el-border);

        .el-button {
          padding: 0;
        }
      }

      .item {
        padding: 0 10px;

        .item-remove {
          padding: 0;
          display: none;
        }
        &:hover {
          background-color: var(--el-fill-color);
          .item-remove {
            display: inline-block;
          }
        }

      }
    }
  }
</style>
